package com.demo.util.lambda.utils;

import com.demo.util.lambda.beans.SFunction;

import java.lang.annotation.Annotation;
import java.lang.invoke.SerializedLambda;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class LambdaUtil {

    public static <T, V, A extends Annotation> Field getSFuncAnnotation(SFunction<T, V> func) throws Exception {
        SerializedLambda serializedLambda = getSerializedLambda(func);
        return getSerializedLambdaField(serializedLambda);
    }

    public static <T, V, A extends Annotation> String getSFuncFieldName(SFunction<T, V> func) throws Exception {
        SerializedLambda serializedLambda = getSerializedLambda(func);
        Field field = getSerializedLambdaField(serializedLambda);
        return field.getName();
    }

    public static <T, V> SerializedLambda getSerializedLambda(SFunction<T, V> func) throws Exception {
        Method writeReplace = func.getClass().getDeclaredMethod("writeReplace");
        writeReplace.setAccessible(true);
        return (SerializedLambda) writeReplace.invoke(func);
    }

    public static <T, V> Field getSerializedLambdaField(SerializedLambda serializedLambda) throws Exception {
        String className = serializedLambda.getImplClass().replace("/", ".");
        String methodName = serializedLambda.getImplMethodName();
        String atteName = getGetFuncAttrName(methodName);
        Class<?> clazz = Class.forName(className);
        return clazz.getDeclaredField(atteName);
    }

    public static <T, V> String getGetFuncAttrName(String methodName) {
        String bigAtteName = methodName.replaceFirst("get", "");
        return bigAtteName.substring(0, 1).toLowerCase() + bigAtteName.substring(1);
    }

}
